package com.ts.api.module.api.service.impl;

import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.date.DateUtils;
import com.gitee.apanlh.util.random.RandomUtils;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;
import com.gitee.apanlh.util.reflection.CopyUtils;
import com.gitee.apanlh.util.valid.Assert;
import com.gitee.apanlh.util.valid.ValidParam;
import com.ts.api.common.context.ApiContext;
import com.ts.api.common.context.ChannelRequestContext;
import com.ts.api.common.localcache.DistrictCache;
import com.ts.api.exp.RollBackException;
import com.ts.api.module.api.entity.ApiUserRequest;
import com.ts.api.module.api.entity.bo.ApiParameterBO;
import com.ts.api.module.api.entity.bo.ApiUserRegisterBO;
import com.ts.api.module.api.entity.po.ApiKeyPO;
import com.ts.api.module.api.service.ApiUserRegister;
import com.ts.api.module.channel.entity.ChannelRequest;
import com.ts.api.module.channel.entity.bo.SelectedUserFormBO;
import com.ts.api.module.channel.entity.bo.UserMappingRegisterBO;
import com.ts.api.module.channel.entity.po.ChannelUserFormPO;
import com.ts.api.module.channel.entity.po.ChannelUserProductMatchPO;
import com.ts.api.module.channel.entity.po.ChannelUserRegisterPO;
import com.ts.api.module.channel.service.DoubleWriteUserService;
import com.ts.api.module.common.entity.DistrictPO;
import com.ts.api.module.product.dao.ProductApplyFlowDao;
import com.ts.api.module.product.dao.ProductUserMatchDao;
import com.ts.api.module.product.entity.po.ProductApplyFlowPO;
import com.ts.cache.form.FormCacheService;
import com.ts.cache.form.entity.FormCache;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class ApiUserRegisterImpl implements ApiUserRegister {

    @Autowired
    private ProductApplyFlowDao productApplyFlowDao;
    @Autowired
    private ProductUserMatchDao productUserMatchDao;
    @Autowired
    private FormCacheService formCacheService;
    @Autowired
    private DoubleWriteUserService doubleWriteUserService;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiUserRegisterBO applyUserRegister(ApiParameterBO apiParameterBO, ProductApplyFlowPO productApplyFlowPO) throws RollBackException {
        ApiKeyPO apiKeyPO = apiParameterBO.getApiKeyPO();

        //  修改日志请求id-一致id
        ApiContext.REQ_ID.remove();
        ApiContext.REQ_ID.set(ClassConvertUtils.toStr(productApplyFlowPO.getReqId()));

        UserMappingRegisterBO userMappingRegisterBO = apiParameterBO.getUserRegisterBO();
        List<SelectedUserFormBO> listSelectUserForm = apiParameterBO.getListUserFormBO();
        Long channelId = apiKeyPO.getLoanChannelId();

        //  注册
        ChannelUserRegisterPO userRegisterPO = CopyUtils.copy(userMappingRegisterBO, ChannelUserRegisterPO.class);
        userRegisterPO.setLoanChannelId(channelId);
        userRegisterPO.setCreateTime(DateUtils.currentTime());
        userRegisterPO.setIsChannelRegister("0");

        //  查询地区编码, 统一城市名称
        DistrictPO districtPO = DistrictCache.getByName(userMappingRegisterBO.getCity());
        if (ValidParam.isNotNull(districtPO)) {
            userRegisterPO.setAreaCode(districtPO.getCode());
            userRegisterPO.setAreaName(districtPO.getName());
        }

        //  性别
        String sex = userRegisterPO.getSex();
        if (ValidParam.isNull(sex)) {
            userRegisterPO.setSex(String.valueOf(RandomUtils.randomInt(0, 1)));
        }

        //  如果是联登量则不重复注册了(因为在校验参数的时候已经修改了用户信息及用户表单参数)
        if (apiParameterBO.getHasFederateUser()) {
            List<ChannelUserFormPO> listChannelFederateUserFormPO = CopyUtils.copyList(listSelectUserForm, ChannelUserFormPO.class);
            ApiUserRegisterBO apiUserRegisterBO = new ApiUserRegisterBO();
            apiUserRegisterBO.setUserRegisterPO(userRegisterPO);
            apiUserRegisterBO.setListUserFormPO(listChannelFederateUserFormPO);
            return apiUserRegisterBO;
        }

        //  插入用户信息
        ChannelUserRegisterPO channelUserRegisterPO = doubleWriteUserService.insertUser(userRegisterPO);
        //  插入用户表单
        List<ChannelUserFormPO> listChannelUserFormPO = CopyUtils.copyList(listSelectUserForm, ChannelUserFormPO.class);
        IteratorUtils.array(listChannelUserFormPO, t -> {
            t.setChannelId(channelId);
            t.setUserId(userRegisterPO.getId());
        });
        doubleWriteUserService.batchInsertUserForm(listChannelUserFormPO);

        ApiUserRegisterBO apiUserRegisterBO = new ApiUserRegisterBO();
        apiUserRegisterBO.setUserRegisterPO(channelUserRegisterPO);
        apiUserRegisterBO.setListUserFormPO(listChannelUserFormPO);
        return apiUserRegisterBO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiUserRegisterBO applyUserRegisterByApiUser(ApiUserRequest apiUserRequest) throws RollBackException {
        Long loanChannelId = apiUserRequest.getLoanChannelId();
        if (ValidParam.isNull(loanChannelId)) {
            throw new RollBackException("注册时缺失渠道来源 rollback");
        }

        String currentTime = DateUtils.currentTime();
        //  用户信息
        ChannelUserRegisterPO userRegisterPO = apiUserRequest.toUserRegister();
        userRegisterPO.setCreateTime(currentTime);
        userRegisterPO.setIsChannelRegister("0");

        //  性别
        String sex = userRegisterPO.getSex();
        if (ValidParam.isNull(sex)) {
            userRegisterPO.setSex(String.valueOf(RandomUtils.randomInt(0, 1)));
        }

        //  查询地区编码, 统一城市名称
        DistrictPO districtPO = DistrictCache.getByName(userRegisterPO.getAreaName());
        userRegisterPO.setAreaCode(districtPO.getCode());
        userRegisterPO.setAreaName(districtPO.getName());

        //  插入用户信息
        doubleWriteUserService.insertUser(userRegisterPO);
        //  插入用户表单信息
        List<FormCache> listFormCache = formCacheService.get();
        List<ChannelUserFormPO> listUserForm = apiUserRequest.toListUserForm(listFormCache);
        IteratorUtils.array(listUserForm, t -> {
            t.setChannelId(loanChannelId);
            t.setUserId(userRegisterPO.getId());
            t.setCreateTime(currentTime);
        });
        doubleWriteUserService.removeByUserId(userRegisterPO.getId());
        doubleWriteUserService.batchInsertUserForm(listUserForm);

        ApiUserRegisterBO apiUserRegisterBO = new ApiUserRegisterBO();
        apiUserRegisterBO.setUserRegisterPO(userRegisterPO);
        apiUserRegisterBO.setListUserFormPO(listUserForm);
        return apiUserRegisterBO;
    }

    @Override
    public void multiBindProductUser(ProductApplyFlowPO insertProductApplyFlowPO, Long userId) throws RollBackException {
        Long channelId = insertProductApplyFlowPO.getLoanChannelId();
        Long loanProductId = insertProductApplyFlowPO.getLoanProductId();
        Long loanProductPlanId = insertProductApplyFlowPO.getLoanProductPlanId();

        //  关联匹配机构
        ChannelUserProductMatchPO userProductMatchPO = new ChannelUserProductMatchPO();
        userProductMatchPO.setLoanChannelId(channelId);
        userProductMatchPO.setLoanProductId(loanProductId);
        userProductMatchPO.setLoanProductPlanId(loanProductPlanId);
        userProductMatchPO.setCreateTime(DateUtils.currentTime());
        userProductMatchPO.setLoanUserId(userId);
        int productRow = productUserMatchDao.insertUserProductMatch(userProductMatchPO);
        Assert.isTrueThrows(productRow > 0, new RollBackException("userProductMatchPO rollback"));

        //  做此判断是为了V3-全流程授权没有ip
        ChannelRequest channelRequest = ChannelRequestContext.get();
        if (ValidParam.isNotNull(channelRequest)) {
            insertProductApplyFlowPO.setFinalIp(channelRequest.getIp());
        }

        int productFlowRow = productApplyFlowDao.insert(insertProductApplyFlowPO);
        Assert.isTrueThrows(productFlowRow > 0, new RollBackException("insertProductApplyFlowPO rollback"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uniqueBindProductUser(ProductApplyFlowPO insertProductApplyFlowPO, Long userId) throws RollBackException {
        Long channelId = insertProductApplyFlowPO.getLoanChannelId();
        Long loanProductId = insertProductApplyFlowPO.getLoanProductId();
        Long loanProductPlanId = insertProductApplyFlowPO.getLoanProductPlanId();

        RLock lock = redissonClient.getLock("bind_product_user:" + userId + "_" + loanProductId);
        lock.lock(20, TimeUnit.SECONDS);
        try {
            //  如果存在条数直接回滚
            int count = productUserMatchDao.countUserProductMatch(userId, loanProductId, channelId);
            if (count > 0) {
                throw new RollBackException("insertUserProductMatch rollback");
            }

            //  关联匹配机构
            ChannelUserProductMatchPO userProductMatchPO = new ChannelUserProductMatchPO();
            userProductMatchPO.setLoanChannelId(channelId);
            userProductMatchPO.setLoanProductId(loanProductId);
            userProductMatchPO.setLoanProductPlanId(loanProductPlanId);
            userProductMatchPO.setCreateTime(DateUtils.currentTime());
            userProductMatchPO.setLoanUserId(userId);
            productUserMatchDao.insertUserProductMatch(userProductMatchPO);
        } finally {
            lock.unlock();
        }

        //  做此判断是为了V3-全流程授权没有ip
        ChannelRequest channelRequest = ChannelRequestContext.get();
        if (ValidParam.isNotNull(channelRequest)) {
            insertProductApplyFlowPO.setFinalIp(channelRequest.getIp());
        }

        int productFlowRow = productApplyFlowDao.insert(insertProductApplyFlowPO);
        Assert.isTrueThrows(productFlowRow > 0, new RollBackException("insertProductApplyFlowPO rollback"));
    }
}
